#pragma once

#include "libtcod.hpp"
#include "libtcod_int.h"

#ifndef NO_OPENGL
#include "../../src/Kernel.h"

#include <glm/glm.hpp>
#include <memory>

namespace Render
{
	class DebugOutput;
	class Shader; typedef std::shared_ptr<Shader> ShaderPtr;
	class Uniform; typedef std::shared_ptr<Uniform> UniformPtr;
}
namespace Scene
{
	class Quad; typedef std::shared_ptr<Quad> QuadPtr;
}
namespace File
{
	class ShaderLoader;
}

namespace GL3
{

typedef enum 
{
	Character,
	ForeCol,
	BackCol,
	ConsoleDataEnumSize
} ConsoleDataEnum;
const int ConsoleDataAlignment[3] = {1, 3, 3 };

class Sys_Opengl3
{
public:
	/* called before creating window */
	static void TCOD_opengl_init_attributes();

	/* call after creating window */
	static bool TCOD_opengl_init_state(int conw, int conh, void *font);
	static bool TCOD_opengl_init_shaders();
	static bool updateTex(ConsoleDataEnum dataType);
	static void updateChar(ConsoleDataEnum dataType, int BufferPos, unsigned char *c, int length, int offset);
	static void TCOD_opengl_putchar_ex(int x, int y, unsigned char c, TCOD_color_t fore, TCOD_color_t back);
	static bool TCOD_opengl_render( int oldFade, bool *ascii_updated, void *console_buffer, void *prev_console_buffer);
	static void TCOD_opengl_swap();
	static void *TCOD_opengl_get_screen();

public:
	static void bind(const Render::ShaderPtr &shader);
	static void setUniforms(	const Render::UniformPtr &uni_termsize,
						const Render::UniformPtr &uni_termcoef,
						const Render::UniformPtr &uni_fontw,
						const Render::UniformPtr &uni_fontcoef,
						const Render::UniformPtr &uni_font,
						const Render::UniformPtr &uni_term,
						const Render::UniformPtr &uni_termfcol,
						const Render::UniformPtr &uni_termbcol);

private:
	static std::unique_ptr<Render::DebugOutput> gl_debug;
	static std::unique_ptr<File::ShaderLoader> shader_loader;
	static glm::mat4 orthoMatrix;
	/* console size (power of 2 and cells) */
	static int POTconwidth, POTconheight, conwidth, conheight;
	/* font texture handle */
	static unsigned int font_tex;
	/* font power of 2 size and pixels */
	static int POTfontwidth,POTfontheight, fontwidth,fontheight;
	/* console data */
	static unsigned int Tex[ConsoleDataEnumSize];
	static unsigned char *data[ConsoleDataEnumSize];
	static bool dirty[ConsoleDataEnumSize];

private:
	static Render::ShaderPtr m_shader;
	static Render::UniformPtr m_uni_termsize;
	static Render::UniformPtr m_uni_termcoef;
	static Render::UniformPtr m_uni_fontw;
	static Render::UniformPtr m_uni_fontcoef;
	static Render::UniformPtr m_uni_font;
	static Render::UniformPtr m_uni_term;
	static Render::UniformPtr m_uni_termfcol;
	static Render::UniformPtr m_uni_termbcol;
	static Scene::QuadPtr m_quad;
};

#endif

}